package com.liangtian.mdm.dm.jsp.util;
/**
 * wy
 */

import com.liangtian.mdm.base.dao.JdbcDao;
import com.liangtian.mdm.dm.config.model.AttrConfig;
import com.liangtian.mdm.dm.listener.CacheUtil;
import com.liangtian.mdm.dm.model.model.Model;
import com.liangtian.mdm.util.ExportUtil;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

@Service
public class ExcelImpUtil {

    @Autowired
    private CacheUtil cacheUtil;
    @Autowired
    private JdbcDao jdbcDao;
    private XSSFWorkbook workBook = null;
    private int isMoreView;//---1:多视图    0:不是
    private boolean isMainTable = true;//---是否主表(   系统里有主从表的结构)
    private List<Map<String, String>> dataList = null;
    private Map<String, String> rowMap = null;
    Map<String, AttrConfig> attrMap = null;//当前主数据如果有从表,则此map用来存储从表中的第一列所关联的主表的属性,
    //校验的时候要用来校验用户填写的这一列是否在主表的sheet也存在,做数据有效性校验要用到,如果不是主从表,则此map没用
    //存储格式为:sheet页名称,对应的主表中关联属性
    Map<String, List<String>> mainTableColumn = null;//当前主数据如果是主从表,则此map用来存储从表中的第一列对应的主表中的数据具体的值,用来校验用户在从表中填写的值是否正确
    //预留出多个从表的结构,按照<从表sheet页名字,对应主表具体值的集合>存储,如果不是主从表,则此map无用
    private StringBuffer errStrAll = null;//错误日志
    private static String[] JOIN_TYPE = {"listTree", "selectList", "popList", "checkBoxType", "radioType"};//关联类型
    private static int CHINA_LENGTH = 3;//校验长度的时候中文占用3个字节
    private static String IS_INT = "^\\+?[1-9][0-9]*$";//整数格式
    private static String IS_FLOAT = "\\d+\\.\\d+$|-\\d+\\.\\d+$";//小数格式
    private static String IS_DATE = "yyyy-MM-dd";//日期格式

    @RequestMapping(value = "excelImport", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> excelImport(List<AttrConfig> configLst, Map<String, List<AttrConfig>> map, HttpServletResponse response, HttpServletRequest request) {
        String fileName = "";
        Map<String, Object> rowMapRet = new HashMap<>();
        try {
            dataList = new ArrayList<Map<String, String>>();
            errStrAll = new StringBuffer();
            String modelId = request.getParameter("modelId");
            Model model = cacheUtil.getModel(modelId);
            isMoreView = model.getIsMoreView();//判断当前模型是否是多视图---1:多视图    0:不是
//        	String classType = model.getClassType();//0:列表 1:父子树 2:分类树

            MultipartHttpServletRequest mulRequest = (MultipartHttpServletRequest) request;
            MultipartFile file = mulRequest.getFile("excel");
            InputStream input = file.getInputStream();
            workBook = new XSSFWorkbook(input);
            if (!MapUtils.isEmpty(map)) {//当前主数据有从表信息---1106---王越---中纺没有主从表结构,先注释掉
//        		attrMap = new HashMap<String,AttrConfig>();
//        		mainTableColumn = new HashMap<String,List<String>>();
//        		for (Map.Entry<String, List<AttrConfig>> entry : map.entrySet()) {
//        			System.out.println(entry.getKey());
//        			String[] keyVal = entry.getKey().split(",,,");
//        			String sheetName = keyVal[1]+"("+keyVal[0]+"_从表)";
//        			XSSFSheet sheet = workBook.getSheet(sheetName);
//        			String error = null;
//        			if(null!=sheet){
//        				AttrConfig mainTabAttrConfig = validataMainTableCol(sheet, configLst);
//            			if(StringUtils.isEmpty(mainTabAttrConfig)){
//            				error = "【设置关联主表列名错误】\r\n";
//            			}else{
//            				attrMap.put(sheetName, mainTabAttrConfig);
//            				isMainTable = false;
//            				error = getSheetInfoToData(sheet,entry.getValue());
//            			}
//        			}else{
//        				error = "【模板有误】\r\n";
//        			}
//        			if(!StringUtils.isEmpty(error)){
//        				errStrAll.append("【"+sheetName+"】sheet页数据校验错误:\r\n\t"+error);
//        			}
//        		}
            } else {
                isMainTable = true;
            }

            XSSFSheet sheet = workBook.getSheetAt(0);
//			int rowNum = sheet.getPhysicalNumberOfRows();//总共多少行
            String zhubiaoRrr = getSheetInfoToData(sheet, configLst);
            if (!isMainTable) {
                zhubiaoRrr = "【" + sheet.getSheetName() + "】sheet页数据校验错误:\r\n\t" + zhubiaoRrr;
            }
            errStrAll.append(zhubiaoRrr);

            System.out.println(dataList + "---" + errStrAll);

//			rowMapRet.put("fileName", fileName);
//			String errText="模板没有数据，请检查完，在操作！";
            if (!StringUtils.isEmpty(errStrAll.toString())) {
                fileName = model.getModelName() + "@@@@" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + ".txt";
                ExportUtil.errTxt(errStrAll.toString(), fileName);
            }
            rowMapRet.put("dataLst", dataList);
            rowMapRet.put("fileName", fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rowMapRet;
    }

    //校验主从表的时候,从表里第一列应该是主表中的某个属性,校验从表sheet页中用户填写的第一个单元格里的数据是否有效
    private AttrConfig validataMainTableCol(XSSFSheet sheet, List<AttrConfig> configLst) {
        XSSFRow row = sheet.getRow(0); // 获取一行
        XSSFCell cell = row.getCell(0);// 获取主从表的时候最左上角的单元格的值(A1的值,判断用户是否有合理的补充这个单元格)
        String val = null;
//		String retStr = null;
        AttrConfig acRet = null;
        if (null != cell && !"".equals(cell)) {
            cell.setCellType(Cell.CELL_TYPE_STRING);
            val = cell.toString().trim();
            String[] str = val.split("\\[");
            if (str.length == 2) {
                String s = str[1].substring(0, str[1].length() - 1);
                for (AttrConfig ac : configLst) {
                    if (s.equals(ac.getAttrName())) {
//						retStr = ac.getAttrId();
                        acRet = ac;
                        break;
                    }
                }
            }
        }
        return acRet;
//		return retStr;
    }

    //按照sheet页验证数据
    private String getSheetInfoToData(XSSFSheet sheet, List<AttrConfig> configLst) {
        StringBuffer errSheet = new StringBuffer();
        boolean isNoData = true;
        for (int i = 0; i < sheet.getPhysicalNumberOfRows(); i++) {// 获取所有行
            XSSFRow row = sheet.getRow(i + isMoreView + 2); // 获取一行
            if (null != row) {
                isNoData = false;
                String error = getRowInfoToData(row, configLst, errSheet);
                if (!StringUtils.isEmpty(error)) {
                    errSheet.append("第" + (i + 1) + "行数据校验失败:" + error + "\r\n");
                }
            }
        }
        if (isNoData) {
            errSheet.append("没有待导入数据,请确认!");
        }
        return errSheet.toString();

    }

    //拼接数据---按照sheet页拼接数据,验证通过的数据会添加到dataList中
    private String getRowInfoToData(XSSFRow row, List<AttrConfig> configLst, StringBuffer errStr) {
        rowMap = new HashMap<String, String>();// 行map
        StringBuffer error = new StringBuffer();
        StringBuffer errorMoreView = new StringBuffer();
        AttrConfig ac = null;
        String groupId = "";
        boolean groupValidate = false;
        for (int j = 0; j < configLst.size(); j++) {
            XSSFCell cell = row.getCell(isMainTable ? j : (j + 1));//这里已经区分了是否是主从表,如果是从表的话第一列是不需要在这里校验的
            ac = configLst.get(j);
            String val = null;
            if (null != cell && !"".equals(cell)) {
                cell.setCellType(Cell.CELL_TYPE_STRING);
                val = cell.toString().trim();
            }
            String err = validateRowData(ac, val);
            if (1 == isMoreView) {//--当前主数据模型是多视图
                if (!StringUtils.isEmpty(val)) {
                    groupValidate = true;
                }
                if (null != ac.getGroupId() && !groupId.equals(ac.getGroupId())) {//--如果当前属性已经是新的试图中的属性
                    groupId = null == ac.getGroupId() ? "" : ac.getGroupId();
                    if (groupValidate) {//主数据模型是多视图并且当前试图需要检验
                        error.append(errorMoreView.toString());
                    }
                    errorMoreView = new StringBuffer();
                }
                errorMoreView.append(err);
            }
            if (0 == isMoreView) {//--当前主数据模型不是多试图
                error.append(err);
            }

        }
        if (StringUtils.isEmpty(errStr) && StringUtils.isEmpty(error)) {
            dataList.add(rowMap);
        }
        return error.toString();
    }

    //待测试---校验数据长度
    private boolean validataLength(AttrConfig ac, String val) {
        String limitLength = ac.getAttrLength();
        int valLength = 0;
        byte[] bytStr = val.getBytes();
        boolean b = false;
        for (int i = 0; i < bytStr.length; i++) {
            if (bytStr[i] < 0)//java中文字符是负的BYTE值
            {
                valLength = valLength + CHINA_LENGTH;//中文占用3个字节
                i = i + 2;
            } else {
                valLength++;
            }
        }
        if (Integer.parseInt(limitLength) < valLength) {
            b = true;
        }
        return b;
    }

    //---校验数据---校验行数据信息
    private String validateRowData(AttrConfig ac, String val) {
        String error = "";
        if (!StringUtils.isEmpty(val) && !"BLOB".equals(ac.getAttrType()) && ac.getAttrType() != null) {//当前cell的值不为空,并且当前属性不是 文件域(需要上传附件)
            if (val.contains("--")) {//如果值里有这个数据,会导致拼出来的sql语句有问题,暂时先屏蔽
                error = "格式错误";
            } else if (Arrays.asList(JOIN_TYPE).contains(ac.getAttrType())) {//-----关联类型
                String sqlForId = "select id from T_" + ac.getDataSourceTable() + " where " + ac.getDataSourceShowColumn() + " = '" + val + "' and  state = 4";
                List<String> ids = jdbcDao.executeSqlSelectId(sqlForId);
                if (0 == ids.size() || ids.size() > 1) {
                    error = "的值不在其属性来源表";
                } else {
                    val = ids.get(0);
                }
            } else if (ac.getAttrType() != null && "DATE".equals(ac.getAttrType())) {//-----日期类型
                SimpleDateFormat sf = new SimpleDateFormat(IS_DATE);
                try {
                    sf.parse(val);
                } catch (ParseException e) {
                    error = "格式应为<日期>";
                }
            } else if (ac.getAttrType() != null && "NUMBER".equals(ac.getAttrType())) {//-----整数
                Pattern pattern = Pattern.compile(IS_INT);
                if (!pattern.matcher(val).matches()) {
                    error = "格式应为<整数>";
                } else if (validataLength(ac, val)) {//-----超长
                    error = "超长,";
                }
            } else if (ac.getAttrType() != null && "NUMBERM".equals(ac.getAttrType())) {//-----小数
                Pattern pattern = Pattern.compile(IS_FLOAT);
                if (!pattern.matcher(val).matches()) {
                    error = "格式应为<小数>";
                } else {//这里需要检验小数的值---分为整数部分和小数部分两部分校验
                    //String[] par = ac.getAttrLength().split(",");
                }
            } else if (ac.getAttrType() != null && "BLOB".equals(ac.getAttrType())) {
                System.out.println("文件域,需要上传附件");
            } else if (ac.getAttrType() != null && "CLOB".equals(ac.getAttrType())) {
                System.out.println("文本");
            } else if (validataLength(ac, val)) {//-----超长
                error = "超长";
            }
        } else if (0 == ac.getIsNull()) {//-----必填
            error = "必填";
        }
        if (StringUtils.isEmpty(error)) {
            rowMap.put(ac.getAttrColumn(), val);
        } else {
            error = "【" + ac.getAttrName() + "】" + error + ";";
        }
        return error;
    }


}
